// "Copyright [2021] <Copyright Han>"

// The topology of this network is shown as the ./oxc_cluster.png
// TODO(Han) : The flexibility is still a problem

package cluster.networks;

import cluster.network_devices.*;
import cluster.task_scheduler.task_generator.*;
import cluster.network_controller.*;
import cluster.dispatcher.*;
import cluster.resource_scheduler.*;
import cluster.task_scheduler.*;
import cluster.network_controller.topo_manager.*;
import cluster.controller_for_test.*;
import inet.networklayer.configurator.ipv4.*;
import inet.node.inet.Router;

network ElecTest
{
    parameters:
        int numMachine = default(2);
        int numOxc = default(2);
        int numOpticalswitch8x64 = default(numMachine);  // Default it is the same as the AIServer num
        int numGpusperMachine = default(8);
        int switch_num = default(numMachine+1);
        int numNvlink_port = default(6);
        int switch_delay = default(0);
        int inetModuleNumber = default(numGpusperMachine * numMachine);
        int TorSwitchPort = default(numGpusperMachine); //(numMachine*numGpusperMachine)/(switch_num-1)
        //int inetModuleNumber = 0;
        // enum ClusterType {
        //    OpticalCluster,
        //    ElectricalCluster,
        //    IbCluster
        //};        
        int clustertype = default(1);

    submodules:
        AIServer[numMachine] : Machine{
            parameters:
                numGpus = numGpusperMachine;
                numNvlink_port = numNvlink_port;
                my_index = index;
        }
        dispatcher : ControllerForTest {}
        topo_manager : TopoManager {}

        configurator: Ipv4NetworkConfigurator {
            parameters:
                @display("p=100,100;is=s");
                dumpAddresses = true;
                dumpTopology = true;
                dumpLinks = true;
                //dumpConfig = "./networkconfig.xml";
                assignAddresses = false;
                inetModuleNum = inetModuleNumber;
                addSubnetRoutes = false;
                optimizeRoutes = false;
                networkType = 1;
                need_index_outputID_map = true;
                switchPortNum = 2*inetModuleNumber;
        }
        adapter:RoutingAdapter {
            parameters:
                numSwitch = switch_num;
        }
        Switch[switch_num]: Router {
            parameters:
            enablePFC = true;
            enableECN = true;  // tmp debug
            **.numPorts = numGpusperMachine*numMachine;
            **.pauseUnit = 1000000000;
        }

    connections allowunconnected:
       // Connect the data plane
        // Connect the machines first
        for i=0..numMachine-1, for j=0..numGpusperMachine-1 {
            AIServer[i].out_port[j] <-->Fiber<--> Switch[i].ethg++;
        }

        for k=0..switch_num-2, for j=0..TorSwitchPort-1 {
            Switch[k].ethg++ <-->Fiber<--> Switch[switch_num-1].ethg++;
        }


        // Connect the dispatcher - AIServer
        for i=0..numMachine-1 {
            dispatcher.machine_port++<-->ControlPlaneLink<-->AIServer[i].controller_port;
        }

       // Connect the switch - centralcontroller
       dispatcher.adapter_port <-->ControlPlaneLink <--> adapter.controller_port;

       // Connect apater and switch
       for i=0..switch_num-1{
           adapter.switch_port++ <--> ControlPlaneLink <--> Switch[i].controlPort;
       }

       // Connect apater and configurator
       configurator.networkConfiguratorOutput  -->ControlPlaneLink -->  adapter.configuration_port;
}
